package own.stu.jobgib.playown.util;

import java.util.*;
import java.util.function.Function;
import java.util.function.Predicate;
import java.util.stream.Collectors;
import java.util.stream.Stream;

public class FunctionUtil {

    public static <T> List<T> filter(List<T> list, Predicate<T> p) {
        return list.stream().filter(p).collect(Collectors.toList());
    }

    @SafeVarargs
    public static <T> List<T> filter(List<T> list, Predicate<T>... mp) {
        Stream<T> stream = list.stream();
        for (Predicate p : mp) {
            stream = stream.filter(p);
        }
        return stream.collect(Collectors.toList());
    }

    public static <T, R> List<R> toList(List<T> list, Function<T, R> func) {
        return list.stream().map(func).distinct().collect(Collectors.toList());
    }

    @SafeVarargs
    public static <T, R> List<R> toListWithFilter(List<T> list, Function<T, R> func, Predicate<T>... mp) {
        Stream<T> stream = list.stream();
        for (Predicate p : mp) {
            stream = stream.filter(p);
        }
        return stream.map(func).collect(Collectors.toList());
    }

    public static <T, R> List<R> toDupList(List<T> list, Function<T, R> func) {
        return list.stream().map(func).distinct().collect(Collectors.toList());
    }

    public static <T, R> Set<R> toSet(List<T> list, Function<T, R> func) {
        return list.stream().map(func).collect(Collectors.toSet());
    }

    public static <T, R> Map<R, List<T>> groupBy(List<T> list, Function<T, R> func) {
        return list.stream().collect(Collectors.groupingBy(func));
    }

    public static <T, R, M> TreeMap<R, List<T>> groupByTreeMap(List<T> list, Function<T, R> func) {
        return list.stream().collect(Collectors.groupingBy(func, TreeMap::new, Collectors.toList()));
    }

    public static <T, R> Map<R, T> toMap(List<T> list, Function<T, R> func) {
        return list.stream().collect(Collectors.toMap(func, Function.identity(), (key1, key2) -> key2));
    }

    public static <T, R> TreeMap<R, T> toTreeMap(List<T> list, Function<T, R> func) {
        return list.stream().collect(Collectors.toMap(func, Function.identity(), (key1, key2) -> key2, TreeMap::new));
    }

    public static <T, K, V> Map<K, V> toMap(List<T> list, Function<T, K> funK, Function<T, V> funV) {
        return list.stream().collect(Collectors.toMap(funK, funV, (key1, key2) -> key2));
    }
}
